package goTeam.up.cs301.go;

import goTeam.up.cs301.game.GamePlayer;
import goTeam.up.cs301.game.LocalGame;
import goTeam.up.cs301.game.actionMsg.GameAction;

import java.util.LinkedList;

/**
 * The GoLocalGame class for a simple go game.  Defines and enforces
 * the game rules; handles interactions with players.
 * 
 * @author Steven R. Vegdahl 
 * @author Matthew Young
 * @author Casey Sigelmann
 * @version November 2013
 */

public class GoLocalGame extends LocalGame implements GoGame {

	// the game's state
	GoState state;
	
	// past states, for Ko rule checking
	LinkedList<GoState> pastStates = new LinkedList<GoState>();

	// the stones for player 0 and player 1, respectively
	private final static char[] mark = {'b','w'};
	
	

	/**
	 * Constructor for the GoLocalGame.
	 */
	public GoLocalGame() {

		// perform superclass initialization
		super();

		// create a new, unfilled-in GoState object
		state = new GoState();
		
		state.gameOver = false;
	}

	/**
	 * Check if the game is over. It is over, return a string that tells
	 * who the winner(s), if any, are. If the game is not over, return null;
	 * 
	 * @return
	 * 		a message that tells who has won the game, or null if the
	 * 		game is not over
	 */
	@Override
	public String checkIfGameOver() {	    
		if (state.gameOver){
			int blackScore = state.getScore('b');
			int whiteScore = state.getScore('w');
			
			if(blackScore > whiteScore){
				return playerNames[0] + " is the winner.";
			}
			if(blackScore < whiteScore){
				return playerNames[1] + " is the winner.";
			}
			return "It's a draw.";
		}

		return null;
	  
	}

	/**
	 * Notify the given player that its state has changed. This should involve sending
	 * a GameInfo object to the player. If the game is not a perfect-information game
	 * this method should remove any information from the game that the player is not
	 * allowed to know.
	 * 
	 * @param p
	 * 			the player to notify
	 */
	@Override
	protected void sendUpdatedStateTo(GamePlayer p) {
		// make a copy of the state, and send it to the player
		p.sendInfo(new GoState(state));

	}

	/**
	 * Tell whether the given player is allowed to make a move at the
	 * present point in the game. 
	 * 
	 * @param playerIdx
	 * 		the player's player-number (ID)
	 * @return
	 * 		true iff the player is allowed to move
	 */
	public boolean canMove(int playerIdx) {
		return playerIdx == state.getWhoseMove();
	}
	

	/**
	 * Makes a move on behalf of a player.
	 * 
	 * @param action
	 * 			The move that the player has sent to the game
	 * @return
	 * 			Tells whether the move was a legal one.
	 */
	@Override
	public boolean makeMove(GameAction action) {
		
		// If it is a passing move handle it
		if(((GoMoveAction) action).isPass()){
			processPass(action);
			return true;
		}
		
		// Otherwise note that it is not and proceed normally
		state.setLastMovePassState(false);
		
		// Operate against a temporary copy of the state
		GoState proposedState = new GoState(this.state);
		
		// get the row and column position of the player's move
		GoMoveAction tm = (GoMoveAction) action;
		int row = tm.getRow();
		int col = tm.getCol();

		// get the 0/1 id of our player
		int playerId = getPlayerIdx(tm.getPlayer());

		// if that space is not blank, indicate an illegal move
		if (proposedState.getPiece(row, col) != ' ') {
			return false;
		}

		// get the 0/1 id of the player whose move it is
		int whoseMove = proposedState.getWhoseMove();

		// place the player's piece on the selected square
		proposedState.setPiece(row, col, mark[playerId]);
		
		// capture pieces
		proposedState.removeCapturedStones(mark[1-playerId]);
		
		
		// Check liberties
		if(!proposedState.hasLiberties(row, col, mark[playerId])){
			return false;
		}
		
		// Check for Ko rule violations
		if(pastStates.contains((proposedState))){
			return false;
		}
		
		pastStates.add(this.state);
		this.state = proposedState;

		// make it the other player's turn
		proposedState.setWhoseMove(1-whoseMove);
		
		// return true, indicating the it was a legal move
		return true;
	}

	/*
	 * Deal with a passing move being made
	 */
	private void processPass(GameAction action) {
		if(state.wasLastMoveAPass()){
			state.gameOver = true;
		}
		else{
			state.setLastMovePassState(true);
		}
		
		// make it the other player's turn
		state.setWhoseMove(1-state.getWhoseMove());
		
	}

}
